#include "mysql_handle.h"
#include <iostream>

MySQLORM* MySQLORM::instance = nullptr;

MySQLORM::MySQLORM(const std::string& server, const std::string& user, const std::string& password, const std::string& database) {
    conn = mysql_init(nullptr);
    if (conn == nullptr) {
        std::cerr << "mysql_init() failed" << std::endl;
        return;
    }
    if (mysql_real_connect(conn, server.c_str(), user.c_str(), password.c_str(), database.c_str(), 0, nullptr, 0) == nullptr) {
        std::cerr << "mysql_real_connect() failed: " << mysql_error(conn) << std::endl;
        mysql_close(conn);
        conn = nullptr;
    }
}

MySQLORM::~MySQLORM() {
    if (conn != nullptr) {
        mysql_close(conn);
    }
}

MySQLORM* MySQLORM::getInstance(const std::string& server, const std::string& user, const std::string& password, const std::string& database) {
    if (instance == nullptr) {
        instance = new MySQLORM(server, user, password, database);
    }
    return instance;
}

bool MySQLORM::insert(const std::string& table, const std::map<std::string, std::string>& data) {
    if (conn == nullptr) {
        return false;
    }
    std::string columns;
    std::string values;
    for (auto it = data.begin(); it != data.end(); ++it) {
        if (it != data.begin()) {
            columns += ", ";
            values += ", ";
        }
        columns += it->first;
        values += "'" + it->second + "'";
    }
    std::string query = "INSERT INTO " + table + " (" + columns + ") VALUES (" + values + ")";
    if (mysql_query(conn, query.c_str()) != 0) {
        std::cerr << "mysql_query() failed: " << mysql_error(conn) << std::endl;
        return false;
    }
    return true;
}

bool MySQLORM::remove(const std::string& table, const std::string& condition) {
    if (conn == nullptr) {
        return false;
    }
    std::string query = "DELETE FROM " + table + " WHERE " + condition;
    if (mysql_query(conn, query.c_str()) != 0) {
        std::cerr << "mysql_query() failed: " << mysql_error(conn) << std::endl;
        return false;
    }
    return true;
}

std::vector<std::map<std::string, std::string>> MySQLORM::select(const std::string& table, const std::string& columns, const std::string& condition) {
    std::vector<std::map<std::string, std::string>> result;
    if (conn == nullptr) {
        return result;
    }
    std::string query = "SELECT " + columns + " FROM " + table;
    if (!condition.empty()) {
        query += " WHERE " + condition;
    }
    if (mysql_query(conn, query.c_str()) != 0) {
        std::cerr << "mysql_query() failed: " << mysql_error(conn) << std::endl;
        return result;
    }
    MYSQL_RES* res = mysql_store_result(conn);
    if (res == nullptr) {
        std::cerr << "mysql_store_result() failed: " << mysql_error(conn) << std::endl;
        return result;
    }
    MYSQL_ROW row;
    MYSQL_FIELD* fields = mysql_fetch_fields(res);
    int num_fields = mysql_num_fields(res);
    while ((row = mysql_fetch_row(res))) {
        std::map<std::string, std::string> row_data;
        for (int i = 0; i < num_fields; ++i) {
            row_data[fields[i].name] = (row[i] ? row[i] : "");
        }
        result.push_back(row_data);
    }
    mysql_free_result(res);
    return result;
}

bool MySQLORM::update(const std::string& table, const std::map<std::string, std::string>& data, const std::string& condition) {
    if (conn == nullptr) {
        return false;
    }
    std::string set_clause;
    for (auto it = data.begin(); it != data.end(); ++it) {
        if (it != data.begin()) {
            set_clause += ", ";
        }
        set_clause += it->first + " = '" + it->second + "'";
    }
    std::string query = "UPDATE " + table + " SET " + set_clause;
    if (!condition.empty()) {
        query += " WHERE " + condition;
    }
    if (mysql_query(conn, query.c_str()) != 0) {
        std::cerr << "mysql_query() failed: " << mysql_error(conn) << std::endl;
        return false;
    }
    return true;
}